home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / cstream.exe / CSTREAM.DOC < prev    next >
Text File  |  1991-06-07  |  11KB  |  363 lines

  1.  
  2.  
  3.      Dear C++ programmer,
  4.  
  5.  
  6.      Thank you for downloading csteam.  The StreamableClass class 
  7.      provides a base class for a polymorphic cluster of 
  8.      streamable classes!  In other words, any class derived from 
  9.      the StreamableClass can be stored on a stream and 
  10.      subsequently loaded from the stream later.  All such classes 
  11.      can be stored in any order and/or mix on the same stream.
  12.  
  13.      The inspiration for my StreamableClass comes from Borland's 
  14.      TurboVision for Turbo Pascal.  A TurboVision for BC++ has 
  15.      been hinted at by Borland but cstream allows you to stream 
  16.      classes NOW without the whole TurboVision tool. Not to 
  17.      mention it's FreeWare.
  18.  
  19.  
  20.  
  21.      Getting Started
  22.      ===============
  23.  
  24.      Copy cstream.hpp to your header directory and cstream.cpp 
  25.      along with csdemo.cpp to your source directory.  Compile 
  26.      csdemo.cpp and cstream.cpp and link (a project file is 
  27.      included, i.e. csdemo.prj).  Run this demo and study its 
  28.      source.
  29.  
  30.  
  31.      In order to make a class streamable, derive it from 
  32.      StreamableClass either publicly or privately.
  33.  
  34.  
  35.     class Employee : public StreamableClass {
  36.         ...
  37.     public:
  38.         StreamableClassID(Employee,StreamableClass,2);
  39.  
  40.         ...
  41.  
  42.         Employee();
  43.         ~Employee();
  44.     };
  45.  
  46.  
  47.      The StreamableClassID macro is used to assign a unique id by 
  48.      which the class can be identified on the stream. This macro 
  49.      also declares several required member functions of which you 
  50.      must define store() and load(). Below is the macro 
  51.      definition as it appears in cstream.hpp.
  52.  
  53.  
  54.     #define StreamableClassID(class, base, id) \
  55.     public:  \
  56.         enum { CLASS_ID = id };  \
  57.     protected:  \
  58.         base :: setID;  \
  59.         class (unsigned cid = CLASS_ID) : base (cid) \
  60.             { return; }  \
  61.     public: \
  62.         base :: ID;  \
  63.         operator StreamC() { return (StreamC)this; }  \
  64.         virtual void store(ostream& os);  \
  65.         static StreamC load(istream& is, StreamC C)
  66.  
  67.  
  68.  
  69.      Your store function should write out to "os" the data 
  70.      members of your class.  Don't worry about the id or any 
  71.      fields in StreamableClass - this is handled automatically.
  72.  
  73.  
  74.     void Employee::store(ostream& os)
  75.     {
  76.         os << name << endf << address << endf
  77.             << cityStateZip << endf;
  78.     }
  79.     
  80.     
  81.      The endf manipulator outputs the end of field terminator 
  82.      which is defined as:
  83.      
  84.      
  85.          char StreamableClass::FieldTermChar = '\n';
  86.  
  87.  
  88.      If you decide to change it, make sure it isn't a character 
  89.      that can be interpreted as part of a number!
  90.      
  91.  
  92.      Your load function should read in the data stored in the 
  93.      extact order it was written out.
  94.  
  95.  
  96.     StreamC Employee::load(istream& is, StreamC C)
  97.     {
  98.         if (!C) if ((C = (StreamC) new Employee())
  99.             == StreamC0)
  100.             return C;
  101.         is.getline(nameBuf,MAX_STR_BUF,
  102.             StreamableClass::FieldTermChar);
  103.         is.getline(addressBuf,MAX_STR_BUF,
  104.             StreamableClass::FieldTermChar);
  105.         is.getline(cityStateZipBuf,MAX_STR_BUF
  106.             ,StreamableClass::FieldTermChar);
  107.         ((EmployeE)C)->construct(nameBuf,addressBuf,
  108.             cityStateZipBuf);
  109.         return C;
  110.     }
  111.  
  112.  
  113.      If the load() function is called to load a class of this 
  114.      type, then C is NULL and load() calls the default 
  115.      constructor for your class as defined in the 
  116.      StreamableClassID() macro above.  This is used simply to 
  117.      satisfy the new operator and to set the ID of the class.  
  118.      Load() can also be called from a derived class in which case 
  119.      C is not NULL!  Your load function should procedure to read 
  120.      the data in, in the order stored by your store() function.  
  121.      To be consistent, all loads call the protected member 
  122.      function, construct(), which you must write, with the data 
  123.      read from the stream.  Your class' regular constructor 
  124.      should typically call construct() to do the nonstream 
  125.      construction of your class.  This way everybody's code using 
  126.      streamable classes will read the same.
  127.  
  128.  
  129.      The trick to streamable classes is in the load() function.  
  130.      It is a static member of StreamableClass and thus has no 
  131.      implicit "this" parameter.  The address of a static function 
  132.      can be taken where as the address of a constructor cannot 
  133.      be! This is why load() is declared as such.  The design of 
  134.      streamable classes in C++ requires that we call a 
  135.      constructor - how else can we insure a portable way of 
  136.      initializing virtual function tables?
  137.  
  138.  
  139.      Note also that load() returns "StreamC", a pointer to a 
  140.      StreamableClass base.  All we know when loading a 
  141.      StreamableClass is that it is a StreamableClass.  You must 
  142.      call the ID() member function, which returns the unique id 
  143.      you defined in the StreamableClassID() macro, to determine 
  144.      its class.
  145.  
  146.  
  147.      If your class is not directly derived from StreamableClass, 
  148.      it still needs to use the StreamableClassID() macro.
  149.  
  150.  
  151.     class Special : Product {
  152.         ...
  153.         void construct(...);
  154.         ...
  155.     public:
  156.         StreamableClassID(Special,Product,4);
  157.         ...
  158.     };
  159.  
  160.  
  161.      Your store() function should call the store() function of 
  162.      its immediate base class before storing its own data 
  163.      members!
  164.  
  165.  
  166.     void Special::store(ostream& os)
  167.     {
  168.         Product::store(os);
  169.         os << specialPrice << endf;
  170.     }
  171.  
  172.  
  173.      Likewise your load() function should call the load() 
  174.      function of its immediate base class before loading its own 
  175.      data members!
  176.  
  177.  
  178.     StreamC Special::load(istream& is, StreamC C)
  179.     {
  180.         if (!C) if ((C = (StreamC) new Special())
  181.             == StreamC0)
  182.             return C;
  183.  
  184.     /***/    Product::load(is,C);  /****/
  185.  
  186.         is >> spriceBuf;
  187.         is.get(); // field term char
  188.         ((SpeciaL)C)->construct(spriceBuf);
  189.         return C;
  190.     }
  191.  
  192.  
  193.  
  194.  
  195.      You should be wondering at this point how the correct static 
  196.      load() function will be called.  We need to back up first 
  197.      and see how to initialize the whole class-stream system. 
  198.      This is done by a global call to the macro 
  199.      StreamableClasses().
  200.  
  201.  
  202.     StreamableClasses(20);
  203.  
  204.     main()
  205.     {
  206.  
  207.         RegisterClass(Employee);
  208.         RegisterClass(Product);
  209.         RegisterClass(Special);
  210.  
  211.         ...
  212.  
  213.         StreamableClass *S1, *S2, *S3;
  214.  
  215.         ifstream iS("emp$prod.cls");
  216.  
  217.         iS >> S1 >> S2 >> S3;
  218.  
  219.         //S1->ID()
  220.  
  221.     }
  222.  
  223.  
  224.      The call here initializes the system to hold a maximum of 20 
  225.      records for different streamable classes in our application.  
  226.      You should set your count appropriately.
  227.  
  228.      The classes to be streamed must be registered before 
  229.      attempting to stream them with a call to the macro, 
  230.      RegisterClass(). The RegisterClass() macro registers your 
  231.      class' ID and load function.
  232.  
  233.      When you go to read back in classes from a stream, define 
  234.      some pointers to StreamableClass and then fetch the classes 
  235.      from the stream to these pointers.  To determine the actual 
  236.      class fetched, call the ID() member function.
  237.  
  238.  
  239.  
  240.      Registration
  241.      ============
  242.  
  243.      If you find cstream useful and are using it in your 
  244.      applications, tell your friends.  You don't need to register 
  245.      cstream -- it's freeware!  All I ask is that you leave my 
  246.      copyright notice intact and to give credit where credit is 
  247.      due!  How about dropping me a line (postcard or email) -- I 
  248.      always like to here your comments and suggestions.  It's 
  249.      also nice to get alittle feedback and know that somebody is 
  250.      really out there!
  251.  
  252.  
  253.  
  254.      Other   Freeware  Goodies  available  for  Borland  C++
  255.      =======================================================
  256.  
  257.  
  258.      pckey    PC keyboard class w/auto enhanced
  259.      gconio      Graphics mode conio class
  260.      cmouse     Mouse Driver class w/ intr handler
  261.      cmdln    Command line parser class
  262.  
  263.  
  264.  
  265.      And Shareware
  266.      =============
  267.  
  268.  
  269.      FlexList II ANSI && K&R C
  270.      FlexList II C++
  271.  
  272.     * Ready-to-run C/C++ linked lists.
  273.     * Hybrid structure: stack,queue,list,array.
  274.     * Stores Heterogeneous/homogeneous data
  275.     * Eliminates the need for parameterized list
  276.         templates such as are proposed for
  277.         C++ in the future.
  278.  
  279.  
  280.      Loose Data Binder C++
  281.